package afcp.alumni.model.db;

//import javax.persistence.Basic;
//import javax.persistence.Column;
//import javax.persistence.Column;
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import afcp.alumni.model.Editable;
import afcp.alumni.model.Pb;
import afcp.alumni.model.base.DatastoreEntity;
import afcp.alumni.search.IndexFilter;
import afcp.alumni.search.Indexable;
import afcp.alumni.security.PasswordEncoder;

import com.google.appengine.api.datastore.Key;

/**
 * <p>
 * Objet métier représentant un utilisateur identifié sur le site.
 * </p>
 * <p>
 * Implémente {@link Serializable} pour stocker l'utilisateur authentifié en
 * variable de session.
 * </p>
 * 
 * @author Antoine
 * 
 */
//@NamedQuery(name = "Member.findAll", query = "SELECT m FROM Member m")
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
@Indexable
public class Member implements DatastoreEntity, Serializable {
	
	public static enum Sex {
		MALE, FEMALE
	}
	public static final String ROLE_MEMBER = "MEMBER";
	public static final String ROLE_ADMIN = "ADMIN";
	public static enum Role {
		ADMIN, MEMBER
	}
	
//	@Persistent
//	@Extension(vendorName = "datanucleus", key = DatastoreEntity.ANNOTATION_PARENT_KEY_VALUE, value = "true")
//	private String mParentEncKey;
 
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public Member() {
	}

	// @GeneratedValue(strategy=GenerationType.IDENTITY)
	@PrimaryKey
//	@Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY) // To allow automatic
	@Persistent
	// generation when saving to datastore
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private Key key;

	@Override
	public Key getKey() {
		return key;
	}

//	/**
//	 * Don't call this method because Member has no ancestor
//	 */
//	@Override
//	public void setKeyWithAncestor(Key ancestorKey) {
//		this.key = KeyFactory.createKey(ancestorKey, this.getClass().getSimpleName(), Util.generateId());
//	}

	@Override
	public String getId() {
//		return key == null ? null : KeyFactory.keyToString(key);
		return email;
	}
//	public void setId(String id) {
//		this.key = KeyFactory.stringToKey(id);
//	}


	// TODO pour les champs indexés (searchable), les regrouper dans un seul
	// champ de la search API pour optimiser.
	
//	@Persistent
//	// Unowned utile ? Essayer de l'enlever.
//	@Unowned
//	@Editable
//	private Login login;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String lastName;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String firstName;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private Sex sex; // TODO ce sont male et female qui sont indexés. Penser à
						// indexer les autres langues en précisant à la search
						// api la langue pour chacun.
	@Persistent
	@Indexable(locale=Indexable.Locale.ZH)
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String chineseName;
	@Persistent
	// TODO ajouter @Searchable et tester
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private Date birthDate;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private int parisTechEntranceYear;
	@Persistent
	@Indexable(locale=Indexable.Locale.FR)
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String parisTechSchool;
	@Persistent
	@Indexable(locale=Indexable.Locale.ZH)
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String chineseUniversity;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String scholarship;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String domainInFrance;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String domainInChina;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String otherDiploma;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String diplomaUniversity;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String firstJobCountry;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String internship;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String firstJob;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String jobCountry;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String employer;
	@Persistent
	@Indexable
//	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String email; // Ajouter une regex ?
	@Persistent
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String phone;
	// TODO ajouter le complément d'adresse et les coordonnées GPS.
	@Persistent
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String addressSupplement;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String address;
	@Persistent
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private double gpsLat;
	@Persistent
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private double gpsLong;
	@Persistent
	@Indexable//(locale=Searchable.Locale.FR)
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String country;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String weibo;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String weixin;
	@Persistent
	@Indexable
	@Editable
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String notes;
	
	// not searchables
	@Persistent
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private String password;
//	@OneToMany(cascade = CascadeType.ALL)
	@Persistent
	@IndexFilter(ROLE_MEMBER)
//	@Unowned
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private List<Role> roles;
	
	// private states
	@Persistent
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private boolean deletable = true;
	@Persistent
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private boolean emailSent = false;
	@Persistent
	@Extension(vendorName="datanucleus", key="gae.unindexed", value="true")
	private boolean passwordChanged = false;
	
	// Not persistent
	@NotPersistent
	private List<Pb> problems = null;
	@NotPersistent
	private List<Pb> warnings = null;
	
	


	/**
	 * Set unencrypted password. This setter will encrypt the password.
	 * @param password the unencrypted password.
	 */
	public void setPassword(String password) {
		this.password = PasswordEncoder.hash(password);
	}
	public void setEncryptedPassword(String encryptedPassword) {
		this.password = encryptedPassword;
	}
	
	
	// TODO dans les erreurs / warnings : ajouter la valeur qui pose problème
	// (changement de modèle d'erreurs dans la liste).
	public List<Pb> getErrors() {
		return problems;
	}
	public void addError(Pb problem) {
		if (problems == null) {
			problems = new LinkedList<>();
		}
		problems.add(problem);
	}
	
	public List<Pb> getWarnings() {
		return warnings;
	}
	public void addWarning(Pb warning) {
		if (warnings == null) {
			warnings = new LinkedList<>();
		}
		warnings.add(warning);
	}
	
	public void setRole(Role role) {
		this.roles = new LinkedList<Role>();
		roles.add(role);
	}
	public boolean noRole() {
		return roles == null || roles.isEmpty();
	}

	
//	public Member updateWith(Member other) {
//		this.setAll(other.firstName, other.lastName, other.sex,
//				other.chineseName, other.birthDate, other.country, other.email,
//				other.phone, other.weibo, other.weixin,
//				other.parisTechEntranceYear, other.parisTechSchool,
//				other.chineseUniversity, other.employer,
//				other.firstJobCountry, other.firstJobCountry);
//		return this;
//	}
	
	// Generated methods:

//	public String getmParentEncKey() {
//		return mParentEncKey;
//	}
//
//	public void setmParentEncKey(String mParentEncKey) {
//		this.mParentEncKey = mParentEncKey;
//	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public Sex getSex() {
		return sex;
	}

	public void setSex(Sex sex) {
		this.sex = sex;
	}

	public String getChineseName() {
		return chineseName;
	}

	public void setChineseName(String chineseName) {
		this.chineseName = chineseName;
	}

	public Date getBirthDate() {
		return birthDate;
	}

	public void setBirthDate(Date birthDate) {
		this.birthDate = birthDate;
	}

	public int getParisTechEntranceYear() {
		return parisTechEntranceYear;
	}

	public void setParisTechEntranceYear(int parisTechEntranceYear) {
		this.parisTechEntranceYear = parisTechEntranceYear;
	}

	public String getParisTechSchool() {
		return parisTechSchool;
	}

	public void setParisTechSchool(String parisTechSchool) {
		this.parisTechSchool = parisTechSchool;
	}

	public String getChineseUniversity() {
		return chineseUniversity;
	}

	public void setChineseUniversity(String chineseUniversity) {
		this.chineseUniversity = chineseUniversity;
	}

	public String getScholarship() {
		return scholarship;
	}

	public void setScholarship(String scholarship) {
		this.scholarship = scholarship;
	}

	public String getDomainInFrance() {
		return domainInFrance;
	}

	public void setDomainInFrance(String domainInFrance) {
		this.domainInFrance = domainInFrance;
	}

	public String getDomainInChina() {
		return domainInChina;
	}

	public void setDomainInChina(String domainInChina) {
		this.domainInChina = domainInChina;
	}

	public String getOtherDiploma() {
		return otherDiploma;
	}

	public void setOtherDiploma(String otherDiploma) {
		this.otherDiploma = otherDiploma;
	}

	public String getDiplomaUniversity() {
		return diplomaUniversity;
	}

	public void setDiplomaUniversity(String diplomaUniversity) {
		this.diplomaUniversity = diplomaUniversity;
	}

	public String getFirstJobCountry() {
		return firstJobCountry;
	}

	public void setFirstJobCountry(String firstJobCountry) {
		this.firstJobCountry = firstJobCountry;
	}

	public String getInternship() {
		return internship;
	}

	public void setInternship(String internship) {
		this.internship = internship;
	}

	public String getFirstJob() {
		return firstJob;
	}

	public void setFirstJob(String firstJob) {
		this.firstJob = firstJob;
	}

	public String getJobCountry() {
		return jobCountry;
	}

	public void setJobCountry(String jobCountry) {
		this.jobCountry = jobCountry;
	}

	public String getEmployer() {
		return employer;
	}

	public void setEmployer(String employer) {
		this.employer = employer;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getAddressSupplement() {
		return addressSupplement;
	}

	public void setAddressSupplement(String addressSupplement) {
		this.addressSupplement = addressSupplement;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public double getGpsLat() {
		return gpsLat;
	}

	public void setGpsLat(double gpsLat) {
		this.gpsLat = gpsLat;
	}

	public double getGpsLong() {
		return gpsLong;
	}

	public void setGpsLong(double gpsLong) {
		this.gpsLong = gpsLong;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getWeibo() {
		return weibo;
	}

	public void setWeibo(String weibo) {
		this.weibo = weibo;
	}

	public String getWeixin() {
		return weixin;
	}

	public void setWeixin(String weixin) {
		this.weixin = weixin;
	}

	public String getNotes() {
		return notes;
	}

	public void setNotes(String notes) {
		this.notes = notes;
	}

	public List<Role> getRoles() {
		return roles;
	}

	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}

	public boolean isDeletable() {
		return deletable;
	}

	public void setDeletable(boolean deletable) {
		this.deletable = deletable;
	}

	public boolean isEmailSent() {
		return emailSent;
	}

	public void setEmailSent(boolean emailSent) {
		this.emailSent = emailSent;
	}

	public boolean isPasswordChanged() {
		return passwordChanged;
	}

	public void setPasswordChanged(boolean passwordChanged) {
		this.passwordChanged = passwordChanged;
	}

	public List<Pb> getProblems() {
		return problems;
	}

	public void setProblems(List<Pb> problems) {
		this.problems = problems;
	}

	public String getPassword() {
		return password;
	}

	public void setKey(Key key) {
		this.key = key;
	}

	public void setWarnings(List<Pb> warnings) {
		this.warnings = warnings;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime
				* result
				+ ((addressSupplement == null) ? 0 : addressSupplement
						.hashCode());
		result = prime * result
				+ ((birthDate == null) ? 0 : birthDate.hashCode());
		result = prime * result
				+ ((chineseName == null) ? 0 : chineseName.hashCode());
		result = prime
				* result
				+ ((chineseUniversity == null) ? 0 : chineseUniversity
						.hashCode());
		result = prime * result + ((country == null) ? 0 : country.hashCode());
		result = prime
				* result
				+ ((diplomaUniversity == null) ? 0 : diplomaUniversity
						.hashCode());
		result = prime * result
				+ ((domainInChina == null) ? 0 : domainInChina.hashCode());
		result = prime * result
				+ ((domainInFrance == null) ? 0 : domainInFrance.hashCode());
		result = prime * result + ((email == null) ? 0 : email.hashCode());
		result = prime * result
				+ ((employer == null) ? 0 : employer.hashCode());
		result = prime * result
				+ ((firstJob == null) ? 0 : firstJob.hashCode());
		result = prime * result
				+ ((firstJobCountry == null) ? 0 : firstJobCountry.hashCode());
		result = prime * result
				+ ((firstName == null) ? 0 : firstName.hashCode());
		long temp;
		temp = Double.doubleToLongBits(gpsLat);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(gpsLong);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result
				+ ((internship == null) ? 0 : internship.hashCode());
		result = prime * result
				+ ((jobCountry == null) ? 0 : jobCountry.hashCode());
		result = prime * result
				+ ((lastName == null) ? 0 : lastName.hashCode());
		result = prime * result + ((notes == null) ? 0 : notes.hashCode());
		result = prime * result
				+ ((otherDiploma == null) ? 0 : otherDiploma.hashCode());
		result = prime * result + parisTechEntranceYear;
		result = prime * result
				+ ((parisTechSchool == null) ? 0 : parisTechSchool.hashCode());
		result = prime * result + ((phone == null) ? 0 : phone.hashCode());
		result = prime * result + ((roles == null) ? 0 : roles.hashCode());
		result = prime * result
				+ ((scholarship == null) ? 0 : scholarship.hashCode());
		result = prime * result + ((sex == null) ? 0 : sex.hashCode());
		result = prime * result + ((weibo == null) ? 0 : weibo.hashCode());
		result = prime * result + ((weixin == null) ? 0 : weixin.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Member other = (Member) obj;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (addressSupplement == null) {
			if (other.addressSupplement != null)
				return false;
		} else if (!addressSupplement.equals(other.addressSupplement))
			return false;
		if (birthDate == null) {
			if (other.birthDate != null)
				return false;
		} else if (!birthDate.equals(other.birthDate))
			return false;
		if (chineseName == null) {
			if (other.chineseName != null)
				return false;
		} else if (!chineseName.equals(other.chineseName))
			return false;
		if (chineseUniversity == null) {
			if (other.chineseUniversity != null)
				return false;
		} else if (!chineseUniversity.equals(other.chineseUniversity))
			return false;
		if (country == null) {
			if (other.country != null)
				return false;
		} else if (!country.equals(other.country))
			return false;
		if (diplomaUniversity == null) {
			if (other.diplomaUniversity != null)
				return false;
		} else if (!diplomaUniversity.equals(other.diplomaUniversity))
			return false;
		if (domainInChina == null) {
			if (other.domainInChina != null)
				return false;
		} else if (!domainInChina.equals(other.domainInChina))
			return false;
		if (domainInFrance == null) {
			if (other.domainInFrance != null)
				return false;
		} else if (!domainInFrance.equals(other.domainInFrance))
			return false;
		if (email == null) {
			if (other.email != null)
				return false;
		} else if (!email.equals(other.email))
			return false;
		if (employer == null) {
			if (other.employer != null)
				return false;
		} else if (!employer.equals(other.employer))
			return false;
		if (firstJob == null) {
			if (other.firstJob != null)
				return false;
		} else if (!firstJob.equals(other.firstJob))
			return false;
		if (firstJobCountry == null) {
			if (other.firstJobCountry != null)
				return false;
		} else if (!firstJobCountry.equals(other.firstJobCountry))
			return false;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (Double.doubleToLongBits(gpsLat) != Double
				.doubleToLongBits(other.gpsLat))
			return false;
		if (Double.doubleToLongBits(gpsLong) != Double
				.doubleToLongBits(other.gpsLong))
			return false;
		if (internship == null) {
			if (other.internship != null)
				return false;
		} else if (!internship.equals(other.internship))
			return false;
		if (jobCountry == null) {
			if (other.jobCountry != null)
				return false;
		} else if (!jobCountry.equals(other.jobCountry))
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		if (notes == null) {
			if (other.notes != null)
				return false;
		} else if (!notes.equals(other.notes))
			return false;
		if (otherDiploma == null) {
			if (other.otherDiploma != null)
				return false;
		} else if (!otherDiploma.equals(other.otherDiploma))
			return false;
		if (parisTechEntranceYear != other.parisTechEntranceYear)
			return false;
		if (parisTechSchool == null) {
			if (other.parisTechSchool != null)
				return false;
		} else if (!parisTechSchool.equals(other.parisTechSchool))
			return false;
		if (phone == null) {
			if (other.phone != null)
				return false;
		} else if (!phone.equals(other.phone))
			return false;
		if (roles == null) {
			if (other.roles != null)
				return false;
		} else if (!roles.equals(other.roles))
			return false;
		if (scholarship == null) {
			if (other.scholarship != null)
				return false;
		} else if (!scholarship.equals(other.scholarship))
			return false;
		if (sex != other.sex)
			return false;
		if (weibo == null) {
			if (other.weibo != null)
				return false;
		} else if (!weibo.equals(other.weibo))
			return false;
		if (weixin == null) {
			if (other.weixin != null)
				return false;
		} else if (!weixin.equals(other.weixin))
			return false;
		return true;
	}
	
	@Override
	public String toString() {
		return "Member [lastName=" + lastName + ", firstName=" + firstName
				+ ", sex=" + sex + ", chineseName=" + chineseName
				+ ", birthDate=" + birthDate + ", parisTechEntranceYear="
				+ parisTechEntranceYear + ", parisTechSchool="
				+ parisTechSchool + ", chineseUniversity=" + chineseUniversity
				+ ", scholarship=" + scholarship + ", domainInFrance="
				+ domainInFrance + ", domainInChina=" + domainInChina
				+ ", otherDiploma=" + otherDiploma + ", diplomaUniversity="
				+ diplomaUniversity + ", firstJobCountry=" + firstJobCountry
				+ ", internship=" + internship + ", firstJob=" + firstJob
				+ ", jobCountry=" + jobCountry + ", employer=" + employer
				+ ", email=" + email + ", phone=" + phone
				+ ", addressSupplement=" + addressSupplement + ", address="
				+ address + ", gpsLat=" + gpsLat + ", gpsLong=" + gpsLong
				+ ", country=" + country + ", weibo=" + weibo + ", weixin="
				+ weixin + ", notes=" + notes + ", roles=" + roles + "]";
	}
	
	
}
